package engine;
import gameobject.Exit;
import gameobject.Object;
import gameobject.Room;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.LinkedList;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JFrame;



public class MouseEventHandler implements MouseListener {
	
	private Map<String, Object> roomItems;
	private Room currentRoom;
	
	// Constants for determining what the mouse action on button 1 currently is
	public static final int TAKING = 1;
	public static final int LOOKING = 2;
	public static final int COMBINING = 3;
	
	public boolean actionActive = false;
	public int mouseX;
	public int mouseY;
	
	// default action on mouse click is "take an object"
	public int action = TAKING;
	
	JFrame mainFrame;
	
	// for item combining
	Object source;
	Object target;

	
	/**
	 * Checks for mouse position depending on the room the player is in
	 * and performs appropriate actions (taking items, walking through doors..)
	 */
	@Override
	public void mouseClicked(MouseEvent e) {

		// get the mainframe
		mainFrame = JLeibniz.mainFrame;
		
		// First, get the room the player is in and all items that are in it
		currentRoom = JLeibniz.getPlayer().getCurrentRoom();
		roomItems = currentRoom.getItems();
		
		// On right click, change the action for left mouse click
		if(e.getButton() == MouseEvent.BUTTON3) {
			if(action == TAKING) {
				action = LOOKING;
				JLeibniz.output("Looking");

			}
			else {
				action = TAKING;
				JLeibniz.output("Taking");
			}
			/*
			 *  reset inventory item positions, since it's possible the player
			 *  picked up an item in his inventory and afterwards clicks right.
			 */
			resetPositions();
			return;

		}
		
		// if the user left clicked, first move the player to the location, then handle
		// appropriately
		if(e.getButton() == MouseEvent.BUTTON1){
		
			/*
			 * First determine if the player clicked outside of the game area.
			 * If so, handle inventory clicking and return.
			 */
			if(!(e.getX() > 30 && e.getX() < 830 && e.getY() > 50 && e.getY() < 650)) {
				inventoryClicking(e);
				return;
			}		
			
			/*
			 * Set destination for the player and activate the moving and 
			 * actionActive flags.
			 */
			JLeibniz.getPlayer().setDestination(e.getX(), e.getY());
			JLeibniz.getPlayer().moving = true;
			actionActive = true;
			
			// save the x and y position for the mouse
			mouseX = e.getX();
			mouseY = e.getY();
			
			/*
			 * The rest is handled in MainFrame. The player moves to his destination
			 * and then performs the action, like taking an object, entering a new
			 * room etc.
			 */
	
		}	
	}

	/*
	 * Inventory clicking. If the player wants to look at an item,
	 * display its description. If the player is in "taking" mode,
	 * initiate a combination. The next inventory item the player
	 * clicks on will be attempted for combination.
	 * 
	 * TODO: I should probably make a helper method for the repeating shit here.
	 */
	private void inventoryClicking(MouseEvent e) {
		if(e.getX() >= 860 && e.getY() >= 100 && e.getX() <= 1010 && e.getY() <= 150
				&& ((MainFrame)mainFrame).item1 != null) {
			
			if(action == LOOKING) {
				JLeibniz.output(((MainFrame)mainFrame).item1.getDescription());
			}
			else if(action == TAKING) {
				// initiate combination
				JLeibniz.output("Combine the "+((MainFrame)mainFrame).item1.getName()+" with" +
						" what?");
				action = COMBINING;
				
				// set source object
				source = ((MainFrame)mainFrame).item1;
			}
			else if(action == COMBINING) {
				target = ((MainFrame)mainFrame).item1;
				source.combine(target);
				action = TAKING;
				
				// Reset the position to its original space
				resetPositions();		
				
			}
			
			
		}
		else if(e.getX() >= 860 && e.getY() >= 160 && e.getX() <= 1010 && e.getY() <= 210
				&& ((MainFrame)mainFrame).item2 != null) {
			
			if(action == LOOKING) {
				JLeibniz.output(((MainFrame)mainFrame).item2.getDescription());
			}
			else if(action == TAKING) {
				// initiate combination
				JLeibniz.output("Combine the "+((MainFrame)mainFrame).item2.getName()+" with" +
						" what?");
				action = COMBINING;
				
				// set source object
				source = ((MainFrame)mainFrame).item2;
			}
			else if(action == COMBINING) {
				target = ((MainFrame)mainFrame).item2;
				source.combine(target);
				action = TAKING;
				
				// Reset the position to its original space
				resetPositions();
			}
			
			
		}
		else if(e.getX() >= 860 && e.getY() >= 220 && e.getX() <= 1010 && e.getY() <= 270
				&& ((MainFrame)mainFrame).item3 != null) {
			
			if(action == LOOKING) {
				JLeibniz.output(((MainFrame)mainFrame).item3.getDescription());
			}
			else if(action == TAKING) {
				// initiate combination
				JLeibniz.output("Combine the "+((MainFrame)mainFrame).item3.getName()+" with" +
						" what?");
				action = COMBINING;
				
				// set source object
				source = ((MainFrame)mainFrame).item3;
			}
			else if(action == COMBINING) {
				target = ((MainFrame)mainFrame).item3;
				source.combine(target);
				action = TAKING;
				
				// Reset the position to its original space
				resetPositions();
			}
			
		}
		else if(e.getX() >= 860 && e.getY() >= 280 && e.getX() <= 1010 && e.getY() <= 330
				&& ((MainFrame)mainFrame).item4 != null) {
			
			if(action == LOOKING) {
				JLeibniz.output(((MainFrame)mainFrame).item4.getDescription());
			}
			else if(action == TAKING) {
				// initiate combination
				JLeibniz.output("Combine the "+((MainFrame)mainFrame).item4.getName()+" with" +
						" what?");
				action = COMBINING;
				
				// set source object
				source = ((MainFrame)mainFrame).item4;
			}
			else if(action == COMBINING) {
				target = ((MainFrame)mainFrame).item4;
				source.combine(target);
				action = TAKING;
				
				// Reset the position to its original space
				resetPositions();
			}
			
		}
		else if(e.getX() >= 860 && e.getY() >= 340 && e.getX() <= 1010 && e.getY() <= 390
				&& ((MainFrame)mainFrame).item5 != null) {
			
			if(action == LOOKING) {
				JLeibniz.output(((MainFrame)mainFrame).item5.getDescription());
			}
			else if(action == TAKING) {
				// initiate combination
				JLeibniz.output("Combine the "+((MainFrame)mainFrame).item5.getName()+" with" +
						" what?");
				action = COMBINING;
				
				// set source object
				source = ((MainFrame)mainFrame).item5;
			}
			else if(action == COMBINING) {
				target = ((MainFrame)mainFrame).item5;
				source.combine(target);
				action = TAKING;
				
				// Reset the position to its original space
				resetPositions();
			}
			
		}
	}
	
	/**
	 * Handles the event when the user wants to take an item.
	 * 
	 */
	private void takeItem(String item, int x, int y) {
		
		if(roomItems.containsKey(item)) {
			// Temporary objects for getting location and size
			Object tempItem = roomItems.get(item);
			ImageIcon tempIcon = new ImageIcon(tempItem.getImagePath());
		
			// Check if the user clicked within the space of the item
			if(x >= tempItem.getX() && y >= tempItem.getY()
					&& x <= tempItem.getX() + tempIcon.getIconWidth()
					&& y <= tempItem.getY() + tempIcon.getIconHeight()) {
				
				// Determine if the player wants to look at the item or take it
				if(action == LOOKING) {
					JLeibniz.output(roomItems.get(item).getDescription());
				}
				else if(action == TAKING) {
					JLeibniz.getPlayer().addToInv(roomItems.get(item));
					roomItems.remove(item);				
					JLeibniz.output("You took the "+item+"!");
				}				
			}
			/*else if(action == LOOKING) {
				JLeibniz.output("Nothing to see here.");
			}*/
			
			// Reset the temporary object and image
			tempItem = null;
			tempIcon = null;
		}
		/*else if(action == LOOKING) {
			JLeibniz.output("Nothing to see here.");
		}*/
		
		// TODO: Reduce the double "Nothing to see here."
			
	}

	/**
	 * Handles clicking inside a room. First check if the user clicked on any
	 * items, then check if he clicked on any exits. If so, do stuff accordingly.
	 */
	public void clickedRoom(int x, int y) {
		
		Room currentRoom = JLeibniz.getPlayer().getCurrentRoom();
		LinkedList<Exit> tempExits = new LinkedList<Exit>();
		
		// handle item clicking in this room
		handleItems(currentRoom.getName(), x, y);
		
		for(int i=0; i < currentRoom.getExits().size(); i++) {
			
			tempExits.add(currentRoom.getExits().get(i));
			
		}
		
		// go through the exit list and handle clicking on them one by one
		while(!tempExits.isEmpty()) {
	
			clickedExit(tempExits.getFirst(), x, y);
			tempExits.removeFirst();
		}

	}
	
	/**
	 * Check if the user clicked on an exit. If so, move him to his new destination.
	 * 
	 * @param exit
	 * @param x
	 * @param y
	 */
	public void clickedExit(Exit exit, int x, int y) {
		
		// Check if the user clicked within the space of the exit
		if(x >= exit.getX() && y >= exit.getY()
				&& x <= exit.getX() + exit.getWidth()
				&& y <= exit.getY() + exit.getHeight()) {
			
			if(action == TAKING) {
				
				JLeibniz.getPlayer().setCurrentRoom(JLeibniz.roomList.get(exit.getDestination()));
			}				
		}
	}
	
	/**
	 * If there are items in the room, handle clicking on them.
	 * 
	 * For some reason, first all items in the room need to be added to
	 * a temporary list. Then iterate through the list while removing
	 * its contents and calling the takeItem() method on each of them to
	 * handle clicking on them.
	 * 
	 * This way, nothing needs to be called explicitely anymore.
	 */
	private void handleItems(String room, int x, int y) {
		
		if(!JLeibniz.roomList.get(room).getItems().isEmpty()) {

			LinkedList<String> tempItems = new LinkedList<String>();
			
			// iterate through all items in the room and handle clicking on them			
			for(String key: roomItems.keySet()) {
				tempItems.add(roomItems.get(key).getName());
			}
			
			while(!tempItems.isEmpty()) {
				takeItem(roomItems.get(tempItems.getFirst()).getName(), x, y);
				tempItems.removeFirst();
			}
		}
	}
	
	/**
	 * Sets inventory items to their original space.
	 */
	private void resetPositions() {
		
		if(((MainFrame)mainFrame).item1 != null) {
			((MainFrame)mainFrame).item1.setX(860);
			((MainFrame)mainFrame).item1.setY(100);
		}
		if(((MainFrame)mainFrame).item2 != null) {
			((MainFrame)mainFrame).item2.setX(860);
			((MainFrame)mainFrame).item2.setY(160);
		}
		if(((MainFrame)mainFrame).item3 != null) {
			((MainFrame)mainFrame).item3.setX(860);
			((MainFrame)mainFrame).item3.setY(220);
		}
		if(((MainFrame)mainFrame).item4 != null) {
			((MainFrame)mainFrame).item4.setX(860);
			((MainFrame)mainFrame).item4.setY(280);
		}
		if(((MainFrame)mainFrame).item5 != null) {
			((MainFrame)mainFrame).item5.setX(860);
			((MainFrame)mainFrame).item5.setY(340);
		}
		
	}
	
	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub		
	}
}
